package com.example.link.service.impl;

import com.example.link.model.AccessCount;
import com.example.link.model.stats.LinkStatsVO;
import com.example.link.service.LinkStatsService;
import lombok.RequiredArgsConstructor;
import com.example.link.mapper.LinkAccessLogMapper;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author qwert
 * @version 1.0.0
 * @create 2025/8/30 14:46
 **/
@Service
@RequiredArgsConstructor
public class LinkStatsServiceImpl implements LinkStatsService {
    private final LinkAccessLogMapper linkAccessLogMapper;

    @Override
    public LinkStatsVO getLinkStatsByShortUrl(String shortUrl) {
        long limitBeginDate = getStartOfDayTimestamp(LocalDate.now().minusDays(7));
        long limitEndDate = getEndOfDayTimestamp(LocalDate.now());

        long startOfToday = getStartOfDayTimestamp(LocalDate.now());
        long endOfToday = getEndOfDayTimestamp(LocalDate.now());

        LinkStatsVO linkStats = new LinkStatsVO();

        // 获取累计访问 pv uv uip
        AccessCount accessCount = getAccessCount(shortUrl);
        linkStats.setTotalStats(LinkStatsVO.TotalStats.builder()
                .pv(accessCount.getTotalAccess())
                .uv(accessCount.getUniqueVisitors())
                .uip(accessCount.getUniqueIPs())
                .build());

        // 获取今日访问统计-小时统计图 today
        linkStats.setHourStats(linkAccessLogMapper.countTodayStatsWithHour(shortUrl, startOfToday));

        // 获取访问统计明细-天折线图 begin-end
        List<LinkStatsVO.DailyStats> dailyStats = linkAccessLogMapper.countStatsWithDaily(shortUrl, limitBeginDate, limitEndDate);
        linkStats.setDailyStats(dailyStats);

        // 获取中国地区访问统计
        linkStats.setChinaStats(LinkStatsVO.countChinaStats());

        // 获取浏览器访问统计
        linkStats.setBrowserStats(linkAccessLogMapper.countBrowserStats(shortUrl));

        // 获取操作系统访问统计
        linkStats.setOsStats(linkAccessLogMapper.countOsStats(shortUrl));

        // 获取访问设备访问统计
        linkStats.setDeviceStats(linkAccessLogMapper.countDeviceStats(shortUrl));

        // 获取网络访问统计
        linkStats.setNetworkStats(linkAccessLogMapper.countNetworkStats(shortUrl));

        return linkStats;
    }


    @Override
    public AccessCount getTodayAccessCount(String shortUrl) {
        long startTime = getStartOfDayTimestamp(LocalDate.now());
        long endTime = getEndOfDayTimestamp(LocalDate.now());
        return getAccessCountByDateRange(shortUrl, startTime, endTime);
    }

    @Override
    public List<AccessCount> getTodayAccessCount() {
        long startTime = getStartOfDayTimestamp(LocalDate.now());
        long endTime = getEndOfDayTimestamp(LocalDate.now());
        return groupAccessCountByDateRange(startTime, endTime);
    }

    @Override
    public AccessCount getAccessCount(String shortUrl) {
        return getAccessCountByDateRange(shortUrl, null, null);
    }

    @Override
    public List<AccessCount> getAccessCount() {
        return groupAccessCountByDateRange(null, null);
    }

    public AccessCount getAccessCountByDateRange(String shortUrl, Long startTime, Long endTime) {
        return linkAccessLogMapper.countAccessStatsByShortUrl(shortUrl, startTime, endTime);
    }

    public List<AccessCount> groupAccessCountByDateRange(Long startTime, Long endTime) {

        Map<String, AccessCount> accessCountMap = linkAccessLogMapper.countAccessStats(startTime, endTime);
        if (accessCountMap == null || accessCountMap.isEmpty()) {
            return List.of(); // 返回空列表，避免 NPE
        }
        return new ArrayList<>(accessCountMap.values());
    }


    /**
     * 获取指定日期当天的起始时间戳
     * @param date 日期
     * @return 当天00:00:00的时间戳
     */
    private long getStartOfDayTimestamp(LocalDate date) {
        LocalDateTime startOfDay = date.atStartOfDay();
        return Timestamp.valueOf(startOfDay).getTime();
    }

    /**
     * 获取指定日期当天的结束时间戳
     * @param date 日期
     * @return 当天23:59:59的时间戳
     */
    private long getEndOfDayTimestamp(LocalDate date) {
        LocalDateTime endOfDay = date.atTime(23, 59, 59, 999_000_000);
        return Timestamp.valueOf(endOfDay).getTime();
    }
}
